/**
  ******************************************************************************
  * @file    usbh_ioreq.c
  * @author  MCD Application Team
  * @version V2.1.0
  * @date    19-March-2012
  * @brief   This file handles the issuing of the USB transactions
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/

#include "usbh_ioreq.h"

/** @addtogroup USBH_LIB
  * @{
  */

/** @addtogroup USBH_LIB_CORE
* @{
*/

/** @defgroup USBH_IOREQ
  * @brief This file handles the standard protocol processing (USB v2.0)
  * @{
  */


/** @defgroup USBH_IOREQ_Private_Defines
  * @{
  */
/**
  * @}
  */


/** @defgroup USBH_IOREQ_Private_TypesDefinitions
  * @{
  */
/**
  * @}
  */



/** @defgroup USBH_IOREQ_Private_Macros
  * @{
  */
/**
  * @}
  */


/** @defgroup USBH_IOREQ_Private_Variables
  * @{
  */
/**
  * @}
  */


/** @defgroup USBH_IOREQ_Private_FunctionPrototypes
  * @{
  */
static USBH_Status USBH_SubmitSetupRequest(USBH_HOST *phost,
        uint8_t *buff,
        uint16_t length);

/**
  * @}
  */


/** @defgroup USBH_IOREQ_Private_Functions
  * @{
  */


/**
  * @brief  USBH_CtlReq
  *         USBH_CtlReq sends a control request and provide the status after
  *            completion of the request
  * @param  pdev: Selected device
  * @param  req: Setup Request Structure
  * @param  buff: data buffer address to store the response
  * @param  length: length of the response
  * @retval Status
  */
USBH_Status USBH_CtlReq(USB_OTG_CORE_HANDLE *pdev,
                        USBH_HOST           *phost,
                        uint8_t             *buff,
                        uint16_t            length)
{
    USBH_Status status;
    status = USBH_BUSY;

    switch(phost->RequestState)
    {
        case CMD_SEND:
            /* Start a SETUP transfer */
            USBH_SubmitSetupRequest(phost, buff, length);
            phost->RequestState = CMD_WAIT;
            status = USBH_BUSY;
            break;

        case CMD_WAIT:
            if(phost->Control.state == CTRL_COMPLETE)
            {
                /* Commands successfully sent and Response Received  */
                phost->RequestState = CMD_SEND;
                phost->Control.state = CTRL_IDLE;
                status = USBH_OK;
            }
            else if(phost->Control.state == CTRL_ERROR)
            {
                /* Failure Mode */
                phost->RequestState = CMD_SEND;
                status = USBH_FAIL;
            }
            else if(phost->Control.state == CTRL_STALLED)
            {
                /* Commands successfully sent and Response Received  */
                phost->RequestState = CMD_SEND;
                status = USBH_NOT_SUPPORTED;
            }

            break;

        default:
            break;
    }

    return status;
}

/**
  * @brief  USBH_CtlSendSetup
  *         Sends the Setup Packet to the Device
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer from which the Data will be send to Device
  * @param  hc_num: Host channel Number
  * @retval Status
  */
USBH_Status USBH_CtlSendSetup(USB_OTG_CORE_HANDLE *pdev,
                              uint8_t *buff,
                              uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 0;
    pdev->host.hc[hc_num].data_pid = HC_PID_SETUP;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = USBH_SETUP_PKT_SIZE;
    return (USBH_Status)HCD_SubmitRequest(pdev, hc_num);
}


/**
  * @brief  USBH_CtlSendData
  *         Sends a data Packet to the Device
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer from which the Data will be sent to Device
  * @param  length: Length of the data to be sent
  * @param  hc_num: Host channel Number
  * @retval Status
  */
USBH_Status USBH_CtlSendData(USB_OTG_CORE_HANDLE *pdev,
                             uint8_t *buff,
                             uint16_t length,
                             uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 0;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;

    if(length == 0)
    {
        /* For Status OUT stage, Length==0, Status Out PID = 1 */
        pdev->host.hc[hc_num].toggle_out = 1;
    }

    /* Set the Data Toggle bit as per the Flag */
    if(pdev->host.hc[hc_num].toggle_out == 0)
    {
        /* Put the PID 0 */
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    }
    else
    {
        /* Put the PID 1 */
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    }

    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}


/**
  * @brief  USBH_CtlReceiveData
  *         Receives the Device Response to the Setup Packet
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer in which the response needs to be copied
  * @param  length: Length of the data to be received
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_CtlReceiveData(USB_OTG_CORE_HANDLE *pdev,
                                uint8_t *buff,
                                uint16_t length,
                                uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 1;
    pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;
    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}


/**
  * @brief  USBH_BulkSendData
  *         Sends the Bulk Packet to the device
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer from which the Data will be sent to Device
  * @param  length: Length of the data to be sent
  * @param  hc_num: Host channel Number
  * @retval Status
  */
USBH_Status USBH_BulkSendData(USB_OTG_CORE_HANDLE *pdev,
                              uint8_t *buff,
                              uint16_t length,
                              uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 0;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;

    /* Set the Data Toggle bit as per the Flag */
    if(pdev->host.hc[hc_num].toggle_out == 0)
    {
        /* Put the PID 0 */
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    }
    else
    {
        /* Put the PID 1 */
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    }

    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}


/**
  * @brief  USBH_BulkReceiveData
  *         Receives IN bulk packet from device
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer in which the received data packet to be copied
  * @param  length: Length of the data to be received
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_BulkReceiveData(USB_OTG_CORE_HANDLE *pdev,
                                 uint8_t *buff,
                                 uint16_t length,
                                 uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 1;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;

    if(pdev->host.hc[hc_num].toggle_in == 0)
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    }
    else
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    }

    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}


/**
  * @brief  USBH_InterruptReceiveData
  *         Receives the Device Response to the Interrupt IN token
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer in which the response needs to be copied
  * @param  length: Length of the data to be received
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_InterruptReceiveData(USB_OTG_CORE_HANDLE *pdev,
                                      uint8_t *buff,
                                      uint8_t length,
                                      uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 1;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;

    if(pdev->host.hc[hc_num].toggle_in == 0)
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    }
    else
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    }

    /* toggle DATA PID */
    pdev->host.hc[hc_num].toggle_in ^= 1;
    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}

/**
  * @brief  USBH_InterruptSendData
  *         Sends the data on Interrupt OUT Endpoint
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer from where the data needs to be copied
  * @param  length: Length of the data to be sent
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_InterruptSendData(USB_OTG_CORE_HANDLE *pdev,
                                   uint8_t *buff,
                                   uint8_t length,
                                   uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 0;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;

    if(pdev->host.hc[hc_num].toggle_in == 0)
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    }
    else
    {
        pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
    }

    pdev->host.hc[hc_num].toggle_in ^= 1;
    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}


/**
  * @brief  USBH_SubmitSetupRequest
  *         Start a setup transfer by changing the state-machine and
  *         initializing  the required variables needed for the Control Transfer
  * @param  pdev: Selected device
  * @param  setup: Setup Request Structure
  * @param  buff: Buffer used for setup request
  * @param  length: Length of the data
  * @retval Status.
*/
static USBH_Status USBH_SubmitSetupRequest(USBH_HOST *phost,
        uint8_t *buff,
        uint16_t length)
{
    /* Save Global State */
    phost->gStateBkp =   phost->gState;
    /* Prepare the Transactions */
    phost->gState = HOST_CTRL_XFER;
    phost->Control.buff = buff;
    phost->Control.length = length;
    phost->Control.state = CTRL_SETUP;
    return USBH_OK;
}


/**
  * @brief  USBH_IsocReceiveData
  *         Receives the Device Response to the Isochronous IN token
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer in which the response needs to be copied
  * @param  length: Length of the data to be received
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_IsocReceiveData(USB_OTG_CORE_HANDLE *pdev,
                                 uint8_t *buff,
                                 uint32_t length,
                                 uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 1;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;
    pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}

/**
  * @brief  USBH_IsocSendData
  *         Sends the data on Isochronous OUT Endpoint
  * @param  pdev: Selected device
  * @param  buff: Buffer pointer from where the data needs to be copied
  * @param  length: Length of the data to be sent
  * @param  hc_num: Host channel Number
  * @retval Status.
  */
USBH_Status USBH_IsocSendData(USB_OTG_CORE_HANDLE *pdev,
                              uint8_t *buff,
                              uint32_t length,
                              uint8_t hc_num)
{
    pdev->host.hc[hc_num].ep_is_in = 0;
    pdev->host.hc[hc_num].xfer_buff = buff;
    pdev->host.hc[hc_num].xfer_len = length;
    pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
    HCD_SubmitRequest(pdev, hc_num);
    return USBH_OK;
}

/**
* @}
*/

/**
* @}
*/

/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/



